#include "queue.h"
#include "pseudo_pkt.h"
#include <sqlite3.h>

#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

#ifdef DEBUG_MEM
extern long mem_free;
extern long mem_alloc;
#endif

#include "detector1.h"


#define MAX_COMMIT   10   // single commit count

//#define SERVER_IP "59.27.92.27"
//#define SERVER_PORT 9999  // UDP Port
#define BUFSIZE 12
#define MAX_SEND_SIZE 1024  // Max size of send 
#define MIN_CMD 20
#define TIMEOUT 10
#define PADDING_SIZE 8

char *saddr="localhost";
int sport=9999;

typedef struct info {   // 32 bytes
  time_t sec;           // 8 bytes
  u_int32_t saddr;      // 4 bytes
  u_int32_t daddr;      // 4 bytes
  u_int16_t dport;      // 2 bytes
  u_int8_t tag;         // 1 bytes
  u_char pad[PADDING_SIZE];
} info_t;

/* Client socket */
int sockfd;
struct sockaddr_in servaddr;

void detector1(void* q)
{
  printf("Starting detector1...\n");
  printf("size of info_t(%d)\n",sizeof(info_t));
  Queue_t *Q;
  Q = (Queue_t*)q;

  pseudo_pkt* f;

  int tf;
  int count = 0;
  
  /* UDP client init */
  int n;
  //int sockfd,n;
  //struct sockaddr_in servaddr;
  char sendbuf[MAX_SEND_SIZE];
  char buf[BUFSIZE];
  char buf2[SAMPLE_SIZE];
  char temp[SAMPLE_SIZE];

  // UDP init
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = inet_addr(saddr);
  servaddr.sin_port = htons(sport);

  //init_conn(&sockfd, &servaddr);
  
  info_t new_info;
  int info_count=0;
  int current_size = 0;
  time_t now;
  time_t last_update;

  last_update = 0;
  
  while(1) {
	// pop queue 1
	f = (pseudo_pkt*)queue_dequeue(Q->Q1);

	// TAG filter
	// USER can be used many applications
	if (f->tag == TAG_USER) {
	  memcpy(temp,f->payload, f->packet_size);
	  tf = is_irc_user_cmd(temp);
	  if (tf != 0) {
		// not irc command
		free(f);
		continue;
	  }
	}
	//print_pkt(f, 1);
	memset(&new_info,0,sizeof(info_t));

	memcpy(&new_info.sec, &f->timestamp.tv_sec, 8);
	memcpy(&new_info.saddr, &f->saddr,4);
	memcpy(&new_info.daddr, &f->daddr,4);
	memcpy(&new_info.dport, &f->dport,2);
	memcpy(&new_info.tag, &f->tag, 1);
	// copy data
	memcpy(&new_info.pad, &f->payload, ((f->payload_size > PADDING_SIZE) ? 8:f->payload_size));

	if (f->tag == TAG_PING ) {
	  // ping is server to client flow
	  memcpy(&new_info.saddr, &f->daddr, 4);
	  memcpy(&new_info.daddr, &f->saddr, 4);
	  memcpy(&new_info.dport, &f->sport, 2);
	}
	else if ( f->tag == TAG_NOTICE) {
	  // "NOTICE AUTH" is from server to client
	  // otherwise from client to server
	  memcpy(temp,f->payload, f->packet_size);
	  if ( is_irc_notice_from_server(temp) == 0) {
	    memcpy(&new_info.saddr, &f->daddr,4);
	    memcpy(&new_info.daddr, &f->saddr,4);
	    memcpy(&new_info.dport, &f->sport,2);
		new_info.tag = TAG_NOTICE_AUTH;
	  }
	}

	if (f->tag == TAG_PRIVMSG)
	  print_pkt(f,1);
	// update count
	now = new_info.sec;
	current_size = info_count * sizeof(info_t);
	printf("[%d]Current size:%d(timeout:%u)\n", info_count,current_size, (now-last_update) );
	memcpy( sendbuf + current_size, &new_info, sizeof(info_t) );

	if ( (info_count > MIN_CMD) || ((now - last_update) > TIMEOUT) ) {
	  // send buf
	  printf("Send(%d)\n", current_size + sizeof(info_t));
	  n = sendto(sockfd, sendbuf, current_size + sizeof(info_t), 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
	  if (n < 0) {
		printf("[%d] Error in sendto\n", n);
		printf("Reconnect UDP socket\n");
		close(sockfd);
		sockfd = socket(AF_INET, SOCK_DGRAM, 0);
		bzero(&servaddr, sizeof(servaddr));
		servaddr.sin_family = AF_INET;
		servaddr.sin_addr.s_addr = inet_addr(saddr);
		servaddr.sin_port = htons(sport);

		//init_conn(sockfd, servaddr);
	  }
	  memset(sendbuf, 0, MAX_SEND_SIZE);
	  current_size = 0;
	  info_count = 0;
	  last_update = now;
	}
	else {
	  info_count++;
	  //last_update = new_info.sec;
	}
	
	free(f);
	// enqueue packet
	//queue_enqueue(Q->logQ, (pseudo_pkt*)f);
  }
  pthread_exit(NULL);
}

int is_irc_user_cmd(char *str)
{
  char *token;
  char *ptr;
  int count = 0;
  token = strtok_r(str, " ", &ptr);
  while (token)
	{
	  printf("Count:%d, str:%s\n", count, token);
	  if (count == 4) {
		// check :
		if (strncmp(token, ":", 1) == 0) {
		  printf("IRC user cmd\n");
		  return 0;
		}
		return -1;
		
	  }
	  token = strtok_r(NULL, " ", &ptr);
	  count ++;
	}
  return -1;
}

int is_irc_notice_from_server(char *str)
{
  char *token;
  char *ptr;
  int count = 0;
  token = strtok_r(str, " ", &ptr);
  while (token)
	{
	  printf("Count:%d, str:%s\n", count, token);
	  if (count >= 1) {
		if (strncmp(token, "AUTH", 4) == 0) {
		  printf("From Server notice\n");
		  return 0;
		}
		else
		  return -1;
	  }
	  token = strtok_r(NULL, " ", &ptr);
	  count ++;
	}
  return -1;
}

/*
 * Init UDP connection
 */
void init_conn(int sockfd, struct sockaddr_in servaddr)
{
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = inet_addr(saddr);
  servaddr.sin_port = htons(sport);
}
